import ELNode from "./type/ELNode";
import { ELStack } from "./ELStack";
import { GraphConfigData, NodeConfig } from "@logicflow/core";
import { ELType, GroupType } from "./type/ELType";
import MyParse from './MyParse';

interface TextEntity {
    x: number,
    y: number,
    value: string,
}

export default class MyContext {
    public endPoints: Record<string, ELNode[]> = {};
    public sourceNum: Record<string, number> = {};

    private nodeMap: Record<string, ELNode> = {};

    private inGrooupNode: Record<string, boolean> = {};

    public elStack: ELStack = new ELStack();

    public startId: string = "start"
    public endId: string = "end";

    public isEnd(id: string): boolean {
        return this.endId === id;
    }

    public isStart(id: string): boolean {
        return this.startId === id;
    }

    public getNodeById(id: string): ELNode {
        return this.nodeMap[id]
    }

    private initEdge(sourceId: string, endId: string, edgeText: string = "") {
        // 循环内外的连接不处理
        if (this.inGrooupNode[sourceId] || this.inGrooupNode[endId]) return;

        if (!this.endPoints[sourceId]) {
            this.endPoints[sourceId] = [];
        }
        const node = this.nodeMap[endId]
        node.comingEdgeText = edgeText;
        this.endPoints[sourceId].push(node);

        if (!this.sourceNum[endId]) {
            this.sourceNum[endId] = 0;
        }
        this.sourceNum[endId]++;
    }


    public init(logicFlow: GraphConfigData) {
        const groupNode: NodeConfig[] = []
        //初始化所有节点并转化为ElNode
        logicFlow.nodes.forEach(node => {
            if (!node.id) return;
            if (node.type === ELType.GROUP) {
                groupNode.push(node);
                return
            }
            this.initELNode(node);
        })
        //最后处理所有的LOOP节点
        groupNode.forEach(node => {
            this.initLoopELNode(node);
        })

        // 初始化start和end节点
        const start: ELNode = new ELNode();
        start.id = this.startId;
        this.nodeMap[this.startId] = start;

        const end: ELNode = new ELNode();
        end.id = this.endId;
        this.nodeMap[this.endId] = end;


        //遍历边
        logicFlow.edges.forEach(edge => {
            const sourceId = edge.sourceNodeId
            const targetId = edge.targetNodeId
            if (!sourceId || !targetId) return;
            //if节点特殊处理
            if (this.nodeMap[sourceId].type === ELType.IF) this.parseIFEdge((edge.text as TextEntity)?.value, sourceId, targetId);
            else this.initEdge(sourceId, targetId, (edge.text as TextEntity)?.value);
        })

        //检查节点，没有起点的连接到start，没有终点的连接到end
        logicFlow.nodes.forEach(node => {
            if (!node.id || this.inGrooupNode[node.id]) return;

            if (!this.endPoints[node.id]) {
                this.initEdge(node.id, this.endId);
            }
            if (!this.sourceNum[node.id]) {
                this.initEdge(this.startId, node.id);
            }
        })

        //没有节点时,只有start和end
        if (logicFlow.nodes.length === 0) {
            this.initEdge(this.startId, this.endId);
        }
    }

    /**
     * 保证IF节点一定有两个分支，尽管可能有undefined
     * 且true分支在前，false分支在后
     * @param text
     * @param sourceId
     * @param targetId
     * @private
     */
    private parseIFEdge(text: string, sourceId: string, targetId: string) {
        const target = this.nodeMap[targetId];
        let ends = this.endPoints[sourceId];
        //@ts-ignore
        if (!ends) ends = [undefined, undefined];
        if (this.isTrueText(text)) {
            if (ends[0]) ends[1] = ends[0];
            ends[0] = target;
        } else if (this.isFalseText(text)) {
            if (ends[1]) ends[0] = ends[1];
            ends[1] = target;
        } else {
            if (!ends[0]) ends[0] = target;
            else ends[1] = target;
        }
        this.endPoints[sourceId] = ends;

        if (!this.sourceNum[targetId]) {
            this.sourceNum[targetId] = 0;
        }
        this.sourceNum[targetId]++;
    }

    private isTrueText(text: string): boolean {
        const texts = ["是", "true", "True", "TRUE"];
        return !!texts.find(t => t === text);
    }

    private isFalseText(text: string): boolean {
        const texts = ["否", "false", "False", "FALSE"];
        return !!texts.find(t => t === text);
    }

    /**
     * 将logicFlow节点转化为ELNode
     *
     * @param lfNode Lf节点
     * @return {@link ELNode}
     */
    private initELNode(lfNode: NodeConfig): ELNode {
        const node: ELNode = new ELNode();
        node.id = lfNode.id as string;
        node.type = this.typeFormat(lfNode.type);

        node.properties = lfNode.properties;

        node.nodeId = lfNode.properties?.nodeId as string;
        node.name = lfNode.properties?.name as string;
        node.groupType = lfNode.properties?.groupType as GroupType;

        node.data = lfNode.properties?.data as string;
        node.aliasId = lfNode.properties?.aliasId as string;
        node.tag = lfNode.properties?.tag as string;
        node.startNum = lfNode.properties?.startNum as number;

        this.nodeMap[node.id] = node;
        return node;
    }

    /**
     * 将logicFlow节点转化为ELNode
     *
     * @param lfNode Lf节点
     * @return {@link ELNode}
     */
    private initLoopELNode(lfNode: NodeConfig) {
        const node: ELNode = this.initELNode(lfNode);

        node.addChild(
            //@ts-ignore
            new MyParse(lfNode.flowData).parse()
        );
        this.nodeMap[node.id] = node;

        // 标记内部节点不需要再次处理了
        //@ts-ignore
        lfNode.flowData.nodes.forEach(node => {
            const id = node.id as string;
            this.inGrooupNode[id] = true;
        });
        // 将连接到GROUP内部的边连接到GROUP
        //@ts-ignore
        lfNode.sourceNodeIds?.forEach(id => {
            this.initEdge(id, node.id)
        })
        //@ts-ignore
        lfNode.targetNodeIds?.forEach(id => {
            this.initEdge(node.id, id)
        })
    }




    private typeFormat(lfType: string): ELType {
        if (lfType === "IF") return ELType.IF;
        if (lfType === "SWITCH") return ELType.SWITCH;
        if (lfType === "GROUP") return ELType.GROUP;
        if (lfType === "AND") return ELType.AND;
        if (lfType === "NOT") return ELType.NOT;
        if (lfType === "OR") return ELType.OR;
        return lfType as ELType;
    }

    public setSourceNum(node: ELNode, num: number) {
        this.sourceNum[node.id] = num;
    }

    public getSourceNum(node: ELNode) {
        const num = this.sourceNum[node.id]
        if (!num) return 0;
        return num;
    }

    public getEndNum(node: ELNode): number {
        const elNodes = this.endPoints[node.id]
        if (!elNodes) return 0;
        return elNodes.length;
    }

    public getEndList(node: ELNode): ELNode[] {
        let elNodes = this.endPoints[node.id];
        if (!elNodes) return [];
        return elNodes;
    }

    public push(node: ELNode) {
        this.elStack.push(node);
    }

    public pop(): ELNode {
        return this.elStack.pop();
    }
    /**
     * 创建一个类似函数的栈环境
     * @param node 
     */
    public createStackEnv(node: ELNode) {
        this.elStack.create();
        const newNode = new ELNode()
        newNode.id = node.id;
        newNode.type = node.type
        newNode.groupType = node.groupType
        newNode.aliasId = node.aliasId
        newNode.name = node.name
        newNode.data = node.data
        newNode.tag = node.tag
        newNode.nodeId = node.nodeId
        newNode.child = node.child
        newNode.comingEdgeText = node.comingEdgeText
        newNode.elString = node.elString

        //group专用
        newNode.startNode = node.startNode
        newNode.breakNode = node.breakNode
        newNode.exceptionNode = node.exceptionNode
        newNode.startNum = node.startNum
        this.elStack.push(newNode);
    }

    /**
     * 退出当前栈空间
     * @returns 下次分析的开始节点
     */
    public quitStackEnv() {
        return this.elStack.quit();
    }

    public setStackEndPoint(node: ELNode) {
        this.elStack.addEndPoint(node);
    }
}